using DynamicModelDemo.EntityFramework;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Migrations.Operations;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace DynamicModelDemo
{
    public class InitDbTableService : BackgroundService, IHostedService
    {
        public ILogger<InitDbTableService> Logger { get; }
        public MyDbContext MyDbContext { get; }
        public InitDbTableService(ILogger<InitDbTableService> logger
            , MyDbContext myDbContext
            )
        {
            Logger = logger;
            MyDbContext = myDbContext;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            try
            {
                await AddTableAsync();
            }
            catch (Exception exp)
            {
                Logger.LogError(exp, "ExecuteAsync");
            }
            finally
            {
                await MyDbContext.DisposeAsync();
            }
        }


        async Task AddTableAsync()
        {
            IServiceProvider serviceProvider = (MyDbContext as IInfrastructure<IServiceProvider>).Instance;
            IDiagnosticsLogger<DbLoggerCategory.Database.Command> CommandLogger = serviceProvider.GetRequiredService<IDiagnosticsLogger<DbLoggerCategory.Database.Command>>();
            IRelationalConnection RelationalConnection = serviceProvider.GetRequiredService<IRelationalConnection>();
            string date = DateTime.Now.ToString("yyyy-MM-dd");
            string tableName = $"students-{date}";
            Logger.LogInformation($"准备创建表:[{tableName}]");
            RelationalCommandParameterObject cmdPara = new RelationalCommandParameterObject(RelationalConnection, null, null, MyDbContext, CommandLogger);
            string eixstsSql = @$"
            select 1 from sys.objects so
            WHERE so.Name='{tableName}'
            ";
            IRawSqlCommandBuilder RawSqlCommandBuilder = serviceProvider.GetRequiredService<IRawSqlCommandBuilder>();
            var existsCmd = RawSqlCommandBuilder.Build(eixstsSql);
            object obj = await existsCmd.ExecuteScalarAsync(cmdPara);
            if (obj is int result && result == 1)
            {
                Logger.LogInformation($"表[{tableName}]已存在!");
                return;
            }
            IMigrator migrator = serviceProvider.GetRequiredService<IMigrator>();
            string createSql = migrator.GenerateScript(null, nameof(DynamicModelDemo.Migrations.InitialStudent), MigrationsSqlGenerationOptions.NoTransactions);
            List<StringBuilder> builders = new List<StringBuilder>();
            {
                string[] lines = createSql.SplitToLines();
                StringBuilder builder = new StringBuilder();
                for (int i = 0; i < lines.Length; i++)
                {
                    var it = lines[i];
                    if (string.Equals(it, "Go", StringComparison.OrdinalIgnoreCase))
                    {
                        builders.Add(builder);
                        builder = new StringBuilder();
                    }
                    else
                    {
                        builder.AppendLine(it);
                    }
                }
                if (!builders.Contains(builder) && builder.Length > 0) builders.Add(builder);
            }
            for (int i = 0; i < builders.Count; i++)
            {
                var sql = builders[i].ToString().Trim();
                if (sql.StartsWith("Create", StringComparison.OrdinalIgnoreCase))
                {
                    Logger.LogInformation($"准备执行:[{sql}]");
                    var cmd = RawSqlCommandBuilder.Build(sql);
                    await cmd.ExecuteNonQueryAsync(cmdPara);
                    Logger.LogInformation($"执行了:[{sql}]");
                }
            }
        }
    }
}
